﻿using Engine;
using Engine.Graphics;
using Engine.Media;
using Game;
using System.Collections.Generic;

namespace Command
{
    public class GlassBlock : Game.GlassBlock
    {
        public new const int Index = 15;

        public static string CommandCategory = "命令方块彩色玻璃";

        public Texture2D Texture;

        public override void Initialize()
        {
            Texture = ContentManager.Get<Texture2D>("Textures/Glass");
        }

        public override int GetFaceTextureSlot(int face, int value)
        {
            int data = Terrain.ExtractData(value);
            Color glassColor = GetCommandColor(data);
            if (IsDefaultColor(glassColor))
            {
                return base.GetFaceTextureSlot(face, value);
            }
            else
            {
                return GetCommandColorAlpha(data);
            }
        }

        public override int GetTextureSlotCount(int value)
        {
            Color glassColor = GetCommandColor(Terrain.ExtractData(value));
            if (IsDefaultColor(glassColor))
            {
                return base.GetTextureSlotCount(value);
            }
            return 4;
        }

        public override IEnumerable<int> GetCreativeValues()
        {
            List<int> creativeValues = new List<int>();
            if (SubsystemCommandDef.DisplayColorBlock)
            {
                for (int i = 0; i < 4096; i++)
                {
                    creativeValues.Add(Index + i * 40 * 16384);
                }
            }
            else
            {
                creativeValues.Add(Index);
            }
            return creativeValues;
        }

        public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
        {
            Color glassColor = GetCommandColor(Terrain.ExtractData(value));
            if (IsDefaultColor(glassColor))
            {
                return base.CreateDebrisParticleSystem(subsystemTerrain, position, value, strength);
            }
            else
            {
                return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, glassColor, GetFaceTextureSlot(0, value), Texture);
            }
        }

        public override string GetCategory(int value)
        {
            if (SubsystemCommandDef.DisplayColorBlock && value != Index) return CommandCategory;
            return base.GetCategory(value);
        }

        public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
        {
            Color glassColor = GetCommandColor(Terrain.ExtractData(value));
            if (IsDefaultColor(glassColor))
            {
                generator.GenerateCubeVertices(this, value, x, y, z, Color.White, geometry.AlphaTestSubsetsByFace);
            }
            else
            {
                generator.GenerateCubeVertices(this, value, x, y, z, glassColor, geometry.GetGeometry(Texture).TransparentSubsetsByFace);
            }
        }

        public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
        {
            Color glassColor = GetCommandColor(Terrain.ExtractData(value));
            if (IsDefaultColor(glassColor))
            {
                BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
            }
            else
            {
                BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size),1, ref matrix, glassColor, glassColor, environmentData, Texture);
            }
        }

        public static Color GetCommandColor(int data)
        {
            int colorData = (data >> 5) & 0xFFF;
            int R = (colorData >> 8) & 0xF;
            int G = (colorData >> 4) & 0xF;
            int B = (colorData & 0xF);
            return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
        }

        public static int SetCommandColor(int value, Color color)
        {
            int data = Terrain.ExtractData(value);
            color -= new Color(15, 15, 15);
            int R = (int)(color.R / 16f) << 8;
            int G = (int)(color.G / 16f) << 4;
            int B = (int)(color.B / 16f);
            int colorData = ((R | G | B) & 0xFFF) << 5;
            data = (data & -131041) | colorData;
            return Terrain.ReplaceData(value, data);
        }

        public static int GetCommandColorAlpha(int data)
        {
            return (data >> 1) & 0xF;
        }

        public static int SetCommandColorAlpha(int value, int alpha)
        {
            int data = Terrain.ExtractData(value);
            alpha = (alpha & 0xF) << 1;
            data = (data & -31) | alpha;
            return Terrain.ReplaceData(value, data);
        }

        public static bool IsDefaultColor(Color color)
        {
            return color.R == 15 && color.G == 15 && color.B == 15;
        }
    }
}